#pragma once
#include <new>
#include <iostream>

using u_char = unsigned char;
using ngx_uint_t = unsigned int;
struct ngx_pool_s;

/*
    nginx内存池工一个线程中可以创建一个独立的nginx内存池来使用
    无需保证线程安全
*/

// 清理函数的类型
typedef void(*ngx_pool_cleanup_pt)(void* data);
struct ngx_pool_cleanup_s {
    ngx_pool_cleanup_pt     handler; // 清理回调函数
    void                    *data; // 传递给回调函数的指针
    ngx_pool_cleanup_s      *next; // 指向下一个清理操作
};


// 小块内存数据头信息
struct ngx_pool_data_t {
    u_char                  *last; // 可分配内存开始位置
    u_char                  *end; // 可分配内存末尾位置
    ngx_pool_s              *next; // 保存下一个内存池的地址
    ngx_uint_t              failed; // 记录当前内存池分配失败的次数
};

// 大块内存类型定义
struct ngx_pool_large_s {
    ngx_pool_large_s        *next; // 下一个大块内存
    void                    *alloc; // 记录分配的大块内存的起始地址
};

// nginx内存池的主结构体类型
struct ngx_pool_s {
    ngx_pool_data_t         d; // 内存池的数据头
    size_t                  max; // 小块内存分配的最大值
    ngx_pool_s              *current; // 小块内存池入口指针
    ngx_pool_large_s        *large; // 大块内存分配入口指针
    ngx_pool_cleanup_s      *cleanup; // 清理函数handler的入口指针
};

// buf 缓冲区 清0
#define ngx_memzero(buf, n)       (void) memset(buf, 0, n)
// 向上调正到邻接 a 的倍数上
#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1))
//  将指针p 向上调正到邻接 a 的倍数上
#define ngx_align_ptr(p, a)                                                   \
    (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
// 小块内存分配考虑字节对齐时的单位
#define NGX_ALIGNMENT sizeof(unsigned long)  /* platform word */

// 默认一个物理页面的大小4K
const int ngx_pagesize              =    4096;
// ngx小块内存池可分配的最大空间
const int NGX_MAX_ALLOC_FROM_POOL   =   ngx_pagesize - 1;
// 定义常量，表示一个默认的ngx内存池开辟的大小
const int NGX_DEFAULT_POOL_SIZE     =   16 * 1024;
// 内存池大小按照16字节进行对齐
const int NGX_POOL_ALIGNMENT        =      16;
// ngx小块内存池最小的size调正成NGX_POOL_ALIGNMEBT临近的倍数
const int  NGX_MIN_POOL_SIZE        =      ngx_align((sizeof(ngx_pool_s) + 2 * sizeof(ngx_pool_large_s)), NGX_POOL_ALIGNMENT);

/*
    移植nginx内存池代码，用OOP实现
*/
class ngx_mem_pool // 无日志功能
{
public:
    ngx_mem_pool(size_t size) {
        if (nullptr == ngx_create_pool(size))
        {
            throw std::bad_alloc();
        }
    }
    ~ngx_mem_pool() {
        std::cout << 1 << std::endl;
        ngx_destroy_pool();
    }

    // 考虑内存字节对齐，从内存池申请size大小的内存
    void *ngx_palloc(size_t size);
    // 不考虑内存字节对齐，从内存池申请size大小的内存
    void *ngx_pnalloc(size_t size);
    // 调用的是ngx_pnalloc实现内存分配，但是会初始化0
    void *ngx_pcalloc(size_t size);
    // 释放大块内存
    void  ngx_pfree(void* p);
    // 内存重置函数
    void  ngx_reset_pool();

    // 添加回调清理操作函数
    ngx_pool_cleanup_s* ngx_pool_cleanup_add(ngx_pool_cleanup_pt handler = nullptr, size_t size = NULL, void* data = nullptr);

private:
    ngx_pool_s *pool;
    // 创建指定size大小的内存池，但是小块内存池不超过1个页面的大小
    void* ngx_create_pool(size_t size);
    // 内存池的销毁函数
    void ngx_destroy_pool();
    // 小块内存分配
    void* ngx_palloc_small(size_t size, ngx_uint_t align);
    // 大块内存分配
    void* ngx_palloc_large(ngx_pool_s *pool, size_t size);
    //  分配新的小块内存池
    void* ngx_palloc_block(ngx_pool_s *pool, size_t size);
};
